package cn.icast.custom.protocol;


import cn.icast.custom.protocol.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.util.List;
/**
 * #######################################################################
 * ##########   【自定义】消息 编解码 类  【 不支持@Sharable 】        ########
 * ##########    不支持 @Sharable注解 因为进来的消息 可能会是不完整的   ########
 * ########################################################################
 * 相当于两个handler合二为一，既能入站 也能做出站处理
 *  <b>魔数     </b>，用来在第一时间判定是否是无效数据包
 *  <b>版本号   </b>，可以支持协议的升级
 *  <b>序列化算法</b>，消息正文到底采用哪种序列化反序列化方式，可以由此扩展，例如：json、protobuf、hessian、jdk
 *  <b>指令类型  </b>，是登录、注册、单聊、群聊... 跟业务相关
 *  <b>请求序号  </b>，为了双工通信，提供异步能力
 *  <b>正文长度  </b>
 *  <b>消息正文  </b>
 */
@Slf4j
public class MessageCodec extends ByteToMessageCodec<Message> {

    @Override
    public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
       // 注意 一般自定义协议固定字节数需要是2的整数倍，不然都不专业
        // 1. 4字节魔数
        out.writeBytes(new byte[]{1,2,3,4});
        //2.  1字节的版本
        out.writeByte(1);
        //3. 1字节的序列化方式  jdk 0,json 1
        out.writeByte(0);
        //4. 1字节的指令类型
        out.writeByte(msg.getMessageType());
        //5.  4个字节请求序号
        out.writeInt(msg.getSequenceId());
         //无意义，对齐填充
        out.writeByte(0xff);
        //6. 获取对象的字节数组,把对象转换成字节数组
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(bos);
        oos.writeObject(msg);
        //转换成字节数组
        byte[] byteArray = bos.toByteArray();
        System.out.println("byteArray长度:"+byteArray.length);
        //7. 4个字节长度
        out.writeInt(byteArray.length);
        //8. 写入正文
        out.writeBytes(byteArray);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        int magicNum = in.readInt();        // 大端4字节的 魔数
        byte version = in.readByte();       // 版本
        byte serializerType = in.readByte();
        byte messageType = in.readByte();
        int sequenceId = in.readInt();
        in.readByte();

        int length = in.readInt();
        final byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);

        // 处理内容
        final ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        final ObjectInputStream ois = new ObjectInputStream(bis);

        // 转成 Message类型
        Message message = (Message) ois.readObject();

        log.debug("{},{},{},{},{},{}",magicNum, version, serializerType, messageType, sequenceId, length);
        log.debug("message{}", message);


        // 将message给下一个handler使用
        out.add(message);

    }
}
